package controllers;
import backend.twitter.TwitterClientFactory;
import com.google.common.base.Strings;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.node.ObjectNode;
import play.cache.Cache;
import play.libs.F;
import play.libs.WS;
import play.mvc.Controller;
import play.mvc.Result;
import java.util.Iterator;
import java.util.concurrent.Callable;
/**
* @author sondre
*/
public class Twitter extends Controller {
public static final int DEFAULT_SEARCH_MAX_COUNT = 100;
public static final int CACHE_EXPIRATION_TWITTER_SEARCH = 60 * 10;
public static Result showRateLimitForResource(final String resource) {
final F.Promise<JsonNode> jsonNodePromise = TwitterClientFactory.create()
.createRequestFor("1.1/application/rate_limit_status.json")
.setQueryParameter("resources", resource)
.get().map(new F.Function<WS.Response, JsonNode>() {
@Override
public JsonNode apply(WS.Response response) throws Throwable {
return response.asJson().findPath("resources");
}
});
return async(jsonNodePromise.map(new F.Function<JsonNode, Result>() {
@Override
public Result apply(JsonNode jsonNode) throws Throwable {
return ok(jsonNode);
}
}));
}
public static Result search(final String searchTerm, final String geoCode) {
try {
return Cache.getOrElse(String.format("twitterSearch?q=%1$s,geocode=%2$s", searchTerm, geoCode),
new TwitterSearchCallable(searchTerm, geoCode), CACHE_EXPIRATION_TWITTER_SEARCH);
} catch (Exception e) {
return internalServerError(e.getMessage());
}
}
private static WS.WSRequestHolder getTwitterSearchRequest(String searchTerm) {
return TwitterClientFactory.create()
.createRequestFor("/1.1/search/tweets.json")
.setQueryParameter("q", searchTerm)
.setQueryParameter("count", Integer.toString(DEFAULT_SEARCH_MAX_COUNT));
}
private static JsonNode mapSearchResult(final JsonNode jsonNode) {
final JsonNode statuses = jsonNode.findPath("statuses");
final Iterator<JsonNode> elementsIterator = statuses.getElements();
ArrayNode resultArray = JsonNodeFactory.instance.arrayNode();
while (elementsIterator.hasNext()) {
final JsonNode status = elementsIterator.next();
final ObjectNode resultNode = mapTweet(status);
resultArray.add(resultNode);
}
return resultArray;
}
private static ObjectNode mapTweet(final JsonNode status) {
final ObjectNode resultNode = JsonNodeFactory.instance.objectNode();
resultNode.put("id", status.findPath("id").getLongValue());
resultNode.put("text", status.findPath("text").getTextValue());
resultNode.put("user", status.findPath("user").findPath("screen_name").getTextValue());
resultNode.put("time", status.findPath("created_at").getTextValue());
final JsonNode inReplyToStatusNode = status.findPath("in_reply_to_status_id");
if(! inReplyToStatusNode.isNull()) {
resultNode.put("replyTo", inReplyToStatusNode.getLongValue());
}
return resultNode;
}
private static class TwitterSearchCallable implements Callable<Result> {
private final String searchTerm;
private final String geoCode;
public TwitterSearchCallable(String searchTerm, String geoCode) {
this.searchTerm = searchTerm;
this.geoCode = geoCode;
}
@Override
public Result call() throws Exception {
final WS.WSRequestHolder twitterSearchRequest = getTwitterSearchRequest(searchTerm);
if (!Strings.isNullOrEmpty(geoCode)) {
twitterSearchRequest.setQueryParameter("geocode", geoCode);
}
final F.Promise<JsonNode> resultJsonPromise = twitterSearchRequest
.get().map(new F.Function<WS.Response, JsonNode>() {
@Override
public JsonNode apply(WS.Response response) throws Throwable {
return mapSearchResult(response.asJson());
}
});
return async(resultJsonPromise.map(new F.Function<JsonNode, Result>() {
@Override
public Result apply(final JsonNode jsonNode) throws Throwable {
return ok(jsonNode);
}
}));
}
}
}